﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using winAppGame.model;
using winAppGame.service;

namespace winAppGame.service
{
    /// <summary>
    /// author:zuowenjun
    /// copyright:www.zuowenjun.cn
    /// 斗地主（跑得快）游戏逻辑实现类
    /// </summary>
    public class DDZGameService
    {
        private List<Pai> allPaiList = null;
        private List<PaiRuleChecker> paiRuleCheckers = null;

        public DDZGameService()
        {
            allPaiList = new List<Pai>();
            foreach (int k in Enum.GetValues(typeof(PaiKind)))
            {
                for (int i = Pai.minPai; i <= Pai.maxPai; i++)
                {
                    allPaiList.Add(new Pai(i, (PaiKind)Enum.Parse(typeof(PaiKind), k.ToString())));
                }
            }

            allPaiList.AddRange(new[] { Pai.guiPai, Pai.guiPlusPai });

            LoadAllPaiRuleCheckers();
        }

        private void LoadAllPaiRuleCheckers()
        {
            paiRuleCheckers = new List<PaiRuleChecker>();
            Type ruleCheckerType = typeof(PaiRuleChecker);
            var ruleCheckerTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "winAppGame.service.rulechecker" && ruleCheckerType.IsAssignableFrom(t)).ToList();
            foreach (var t in ruleCheckerTypes)
            {
                var instance = Activator.CreateInstance(t);
                paiRuleCheckers.Add(instance as PaiRuleChecker);
            }
        }

        /// <summary>
        /// 分牌（3人）
        /// </summary>
        /// <returns></returns>
        public Tuple<List<Pai>, List<Pai>, List<Pai>> FenPais()
        {
            var tmpAllPaiList = allPaiList.OrderBy(p => Guid.NewGuid()).ToList();
            int personIndex = 0;
            List<Pai> firstPais = new List<Pai>();
            List<Pai> secondPais = new List<Pai>();
            List<Pai> thirdPais = new List<Pai>();
            foreach (var pai in tmpAllPaiList)
            {
                personIndex++;
                if (personIndex == 1)
                {
                    firstPais.Add(pai);
                }
                else if (personIndex == 2)
                {
                    secondPais.Add(pai);
                }
                else
                {
                    thirdPais.Add(pai);
                    personIndex = 0;
                }
            }

            return Tuple.Create(firstPais.OrderBy(p => p.Value).ToList(),
                secondPais.OrderBy(p => p.Value).ToList(),
                thirdPais.OrderBy(p => p.Value).ToList());
        }

        /// <summary>
        /// 检查出牌是否符合规则
        /// </summary>
        /// <param name="selectedPais"></param>
        /// <param name="lastShowPais"></param>
        /// <param name="lastShowPaiRuleType"></param>
        /// <returns></returns>
        public PaiRuleCheckResult CheckPais(IEnumerable<Pai> selectedPais, IEnumerable<Pai> lastShowPais, PaiRuleType.PaiRuleTypeItem lastShowPaiRuleType)
        {
            List<PaiRuleChecker> currentRuleCheckers;
            if (lastShowPaiRuleType != null)
            {
                if (lastShowPaiRuleType == PaiRuleType.Max)
                {
                    return PaiRuleCheckResult.Failed("要不起！");
                }

                currentRuleCheckers = new List<PaiRuleChecker>();
                //加入炸弹规则验证
                if (lastShowPaiRuleType != PaiRuleType.Four && selectedPais.Count() == 4)
                {
                    currentRuleCheckers.Add(paiRuleCheckers.Single(c => c.ForRuleTypes.Contains(PaiRuleType.Four)));
                }
                else if (lastShowPaiRuleType != PaiRuleType.Max && selectedPais.Count() == 2)
                {
                    currentRuleCheckers.Add(paiRuleCheckers.Single(c => c.ForRuleTypes.Contains(PaiRuleType.Max)));
                }

                currentRuleCheckers.AddRange(paiRuleCheckers.Where(c => c.ForRuleTypes.Contains(lastShowPaiRuleType)).ToList());
            }
            else
            {
                currentRuleCheckers = paiRuleCheckers.Where(c => c.ForBaseCount == selectedPais.Count()
                                                     || (c.ForBaseCount < selectedPais.Count() && c.ForIncrementCount > 0 && (selectedPais.Count() - c.ForBaseCount) % c.ForIncrementCount == 0)).ToList();
            }

            PaiRuleCheckResult checkResult = PaiRuleCheckResult.Failed("出牌规则不正确或要不起！");
            foreach (var ruleChecker in currentRuleCheckers)
            {
                checkResult = ruleChecker.Check(selectedPais, lastShowPais, lastShowPaiRuleType);
                if (checkResult.AllowShow)
                {
                    return checkResult;
                }
            }

            return checkResult;
        }

        public PaiRuleCheckResult AutoSelectPais(IEnumerable<Pai> currentPais, IEnumerable<Pai> lastShowPais, PaiRuleType.PaiRuleTypeItem lastShowPaiRuleType)
        {
            var groupPais = GroupPais(currentPais);
            var candidateRuleCheckers = new List<PaiRuleChecker>();
            if (lastShowPaiRuleType != null)
            {
                if (lastShowPaiRuleType == PaiRuleType.Max)
                {
                    return PaiRuleCheckResult.Failed("要不起！");
                }

                candidateRuleCheckers.AddRange(paiRuleCheckers.Where(c => c.ForRuleTypes.Contains(lastShowPaiRuleType)));

                //加入炸弹出牌规则
                if (groupPais.Count(t => t.Key.Name.ToLower() == Pai.guiPai.Name) == 2 && !candidateRuleCheckers.Any(t => t.ForRuleTypes.Contains(PaiRuleType.Max)))
                {
                    candidateRuleCheckers.Add(paiRuleCheckers.Single(c => c.ForRuleTypes.Contains(PaiRuleType.Max)));
                }

                if (groupPais.Any(t => t.Value == 4) && !candidateRuleCheckers.Any(t => t.ForRuleTypes.Contains(PaiRuleType.Four)))
                {
                    candidateRuleCheckers.Add(paiRuleCheckers.Single(c => c.ForRuleTypes.Contains(PaiRuleType.Four)));
                }

                if (!candidateRuleCheckers.HasItem())
                {
                    return PaiRuleCheckResult.Failed("要不起！");
                }

                foreach (var ruleChecker in candidateRuleCheckers)
                {
                    var result = ruleChecker.AutoSelectPais(groupPais, lastShowPais, lastShowPaiRuleType);
                    if (result.AllowShow)
                    {
                        return result;
                    }
                }

                return PaiRuleCheckResult.Failed("要不起！");
            }

            var ruleTypes = PaiRuleType.Items().Select(t => t.Value).OrderBy(t => t.Priority);

            var result2 = PaiRuleCheckResult.Failed("要不起！");
            foreach (var ruleType in ruleTypes)
            {
                var ruleCheckers = paiRuleCheckers.Where(c => c.ForRuleTypes.Contains(ruleType));
                foreach (var ruleCheck in ruleCheckers)
                {
                    result2 = ruleCheck.AutoSelectPais(groupPais, lastShowPais, ruleType);
                    if (result2.AllowShow)
                    {
                        return result2;
                    }
                }
            }
            return result2;
        }


        private Dictionary<Pai, int> GroupPais(IEnumerable<Pai> pais)
        {
            var groupDic = new Dictionary<Pai, int>();
            foreach (var pai in pais)
            {
                if (groupDic.ContainsKey(pai))
                {
                    groupDic[pai] += 1;
                }
                else
                {
                    groupDic[pai] = 1;
                }
            }
            return groupDic;
        }



    }


}
